#include "SoftIIC.h"
#include "Delay.h"
extern USART cout;
bool SoftIIC::checkACK() const
{
    uint8_t tick = 0;
    this->setSDAIn();
    // *this->SDA_O = 1;
    *this->SCK = 1;
    while (*this->SDA_I and tick++ < 250);
    *this->SCK = 0;
    return tick < 250;
}

void SoftIIC::writeByte(uint8_t byte) const
{
    *this->SCK = 0;
    this->setSDAOut();
    for (uint8_t i = 0;i < 8;i++)
    {
        *this->SDA_O = (byte & 0x80) >> 7;
        byte <<= 1;
        Delay.us(1);
        *this->SCK = 1;
        Delay.us(1);
        *this->SCK = 0;
    }
}

uint8_t SoftIIC::readByte(bool ack) const
{
    uint8_t buf;
    this->setSDAIn();
    for (uint8_t i = 0;i < 8;i++)
    {
        *this->SCK = 0;
        Delay.us(1);
        *this->SCK = 1;
        Delay.us(1);
        buf <<= 1;
        buf |= *this->SDA_I;
        
    }
    this->ACK(ack);
    return buf;
}

SoftIIC::SoftIIC(GPIO_TypeDef* SDA_GPIOx, uint8_t SDA_Num, GPIO_TypeDef* SCK_GPIOx, uint8_t SCK_Num) :clearBit(getClearBit32(SDA_Num))
{
    GPIO::Bit _SDA(SDA_GPIOx, SDA_Num), _SCK(SCK_GPIOx, SCK_Num);
    this->SDA_I = _SDA.GetI();
    this->SDA_O = _SDA.GetO();
    this->SCK = _SCK.GetO();
    this->SDA_GPIO = SDA_GPIOx;
    this->SDA_Num = SDA_Num;
}

BasicIO::Resault SoftIIC::Read(const uint32_t address, void* buffer, uint32_t length) const
{
    auto tool = static_cast<uint8_t*>(buffer);
    this->generateStart();
    this->writeByte(((uint8_t)(address >> 24)) & 0xFE);
    if (not this->checkACK())
    {
        this->generateStop();
        return BasicIO::Fail;
    }
    this->writeByte((uint8_t)(address & 0x1FFFFFF));
    if (not this->checkACK())
    {
        this->generateStop();
        return BasicIO::Fail;
    }
    this->generateStart();
    this->writeByte(((uint8_t)(address >> 24)) | 0x01);
    if (not this->checkACK())
    {
        this->generateStop();
        return BasicIO::Fail;
    }
    while (length--)
    {
        *tool++ = this->readByte();
        // if (not this->checkACK())
        // {
        //     this->generateStop();
        //     return BasicIO::Fail;
        // }
    }
    this->ACK(false);
    this->generateStop();
    return BasicIO::Succ;
}

BasicIO::Resault SoftIIC::Write(const uint32_t address, const void* buffer, uint32_t length) const
{
    auto tool = static_cast<const uint8_t*>(buffer);
    this->generateStart();
    this->writeByte(((uint8_t)(address >> 24)) & 0xFE);//从设备地址
    if (not this->checkACK())
    {
        this->generateStop();
        return BasicIO::Fail;
    }
    this->writeByte((uint8_t)(address & 0x1FFFFFF));
    if (not this->checkACK())
    {
        this->generateStop();
        return BasicIO::Fail;
    }
    while (length--)
    {
        this->writeByte(*tool++);
        if (not this->checkACK())
        {
            this->generateStop();
            return BasicIO::Fail;
        }
    }
    this->generateStop();
    return BasicIO::Succ;
}
